package com.dubbo.ratelimit.limit;

import com.google.common.util.concurrent.RateLimiter;

import java.util.concurrent.TimeUnit;

/**
 *   https://blog.csdn.net/ityouknow/article/details/81230412
 *  服务降级，当服务器压力剧增的情况下，根据当前业务情况及流量对一些服务和页面有策略的降级，
 *      以此释放服务器资源以保证核心任务的正常运行。
 *    1、将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用
 *     限制接口的请求__应用层面 1、令牌头 漏桶 前置：nginx
 *   模拟演示令牌桶和漏桶的差异
 *   zj: 次要服务延迟使用、暂停使用。。
 *   初始化漏桶 ：RateLimiter __指定请求数量、速率
 *          延迟使用__线程阻塞获取      rateLimiter.acquire()
 *          暂停使用__中断逻辑处理  rateLimiter.tryAcquire()
 *              数据库压力撤掉即可
 */
public class GuavaTokenDemo {
    private int qps;
    private int countOfReq;

    private RateLimiter rateLimiter;

    public GuavaTokenDemo(int qps,int countOfReq){
        this.qps=qps;
        this.countOfReq=countOfReq;
    }

    //初始化一个令牌桶
    public GuavaTokenDemo processWithTokenBucket(){
        rateLimiter=RateLimiter.create(qps);
        return this;
    }

    /**
     *  初始化一个漏桶，热身期没有足够的请求(unused),则起速率会逐渐降低到冷却状态
     *  热身时间：可以根据请求动态扩展令牌释放的速率
     */
    public GuavaTokenDemo processWithLeakyBucket(){
        rateLimiter=RateLimiter.create(qps,0,TimeUnit.MILLISECONDS);
        return this;
    }

    private void processRequest(){
        long start=System.currentTimeMillis();
        for(int i=0;i<countOfReq;i++){
            rateLimiter.acquire();
            //获取令牌 阻塞获取
        }

        long end=System.currentTimeMillis()-start;
        System.out.println("处理的请求数量:"+countOfReq+"," +
                ""+"耗时:"+end+",qps:"+rateLimiter.getRate()+",实际qps:"+
                Math.ceil(countOfReq/(end/1000.00)));
    }
    private void doProcessor() throws InterruptedException {
        for(int i=0;i<20;i=i+5){
            TimeUnit.SECONDS.sleep(i);
            processRequest();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new GuavaTokenDemo(50,100).processWithTokenBucket().doProcessor();
        new GuavaTokenDemo(50,100).processWithLeakyBucket().doProcessor();
    }

}
